#include "vm.h"

typedef enum
{
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    R8,
    R9,
    R10,
    R11,
    R12,
    R13,
    R14,
    R15,
    REGISTER_SIZE
} Registers;

typedef enum
{
    FLAG = 12,
    SP,
    LR,
    IP
} RegistersAlias;

Map registers_mapping[] = { // 寄存器字符串到寄存器数字编号映射
    {"r0", R0},
    {"r1", R1},
    {"r2", R2},
    {"r3", R3},
    {"r4", R4},
    {"r5", R5},
    {"r6", R6},
    {"r7", R7},
    {"r8", R8},
    {"r9", R9},
    {"r10", R10},
    {"r11", R11},
    {"r12", R12},
    {"r13", R13},
    {"r14", R14},
    {"r15", R15},
    {"sp", R13},
    {"lr", R14},
    {"ip", R15}};

#define STACK_SIZE 100 // 预定义栈空间大小
#define LINE_SIZE 100  // 预定义每一行指令的长度，是字符串的长度

static int registers[REGISTER_SIZE] = {0}; // 寄存器空间，这里也可以使用malloc动态申请内存空间
static int stack[STACK_SIZE] = {0}; // 栈空间，这里也可以使用malloc动态申请内存空间
static byte enable_debug = 0;

static int get_stack_value(int index)
{
    if (index > STACK_SIZE)
    {
        printf("stack overflow error.\n");
        return -1;
    }
    return stack[index];
}

static void set_stack_value(int value)
{
    registers[SP]++;
    if (registers[SP] > STACK_SIZE)
    {
        printf("stack overflow error.\n");
        return;
    }
    stack[registers[SP]] = value;
}

static void registers_init()
{
    for (size_t i = 0; i < REGISTER_SIZE; i++)
    {
        registers[i] = 0;
    }
}

static bool _validate_register(int reg)
{ // 如果寄存器不存在，则返回false
    bool result = true;
    if (reg < R0 || reg > R15)
        result = false;

    return result;
}

static int get_register_value(int reg)
{ // 如果值不存在，则返回-1
    if (_validate_register(reg) == false)
    {
        printf("unknow register.\n");
        return -1;
    }
    return registers[reg];
}

static void set_register_value(int reg, int value)
{
    if (_validate_register(reg) == false)
    {
        printf("unknow register.\n");
        return;
    }
    registers[reg] = value;
}

static void _clear_buffer(char buf[])
{ // 清空buffer
    for (size_t i = 0; i < LINE_SIZE; i++)
    {
        buf[i] = ' ';
    }
}

static size_t _get_buffer_size(char buf[]) // 获取有效buffer的长度
{
    size_t result = 0;
    for (size_t i = 0; i < LINE_SIZE; i++)
    {
        if (buf[i] != ' ')
            result++;
    }
    return result;
}

vmState *vm_init() // 初始化虚拟机
{
    vmState *vm = malloc(sizeof(vmState)); // 根据虚拟机结构体大小申请相应大小的内存空间
    for (size_t i = 0; i < DEFAULT_SIZE; i++)
    {
        vm->maps[i] = malloc(sizeof(Map));// 为虚拟机存放的指令申请字典空间
    }
    vm->map_index = 0;          // 虚拟机字典索引
    vm->instruction_count = 0;  // 指令条数
    vm->instruction_index = -1; // 初始化虚拟机栈指针
    vm->is_halt = false;
    return vm;
}

static int is_label_address(vmState *vm, char *str)
{
    int result = -1;
    for (size_t i = 0; i < vm->instruction_count; i++)
    {
        if (strcmp(vm->maps[i]->key, str) >= 0)
        {
            result = vm->maps[i]->value;
        }
    }
    return result;
}

static int is_number(char *str)
{
    int result = -1;
    char t[20];
    if (str[0] == '#')
    {
        for (size_t i = 1; i < strlen(str); i++)
        {
            t[i - 1] = str[i];
        }
        result = atoi(t);
    }
    return result;
}

static int get_register(char *str)
{
    int result = -1;
    for (size_t i = 0; i < REGISTER_SIZE; i++)
    {
        if (strcmp(registers_mapping[i].key, str) >= 0)
        {
            result = registers_mapping[i].value;
        }
    }
    return result;
}

static int get_value_by_instruction(vmState *vm, char *instr)
{
    if (get_register(instr) >= 0)
    {
        return get_register_value(get_register(instr));
    }
    else if (is_number(instr) >= 0)
    {
        return is_number(instr);
    }
    else if (is_label_address(vm, instr) >= 0)
    {
        return is_label_address(vm, instr) - 1; // 当前位置减1,因为出了这个函数就是while循环，下一条指令就是IP++，因此这里要-1，防止跳过这条指令没有执行
    }
    else
    {
        printf("unknow type: %s.\n", instr);
        return -1;
    }
}

void vm_next_instruction(vmState *vm)
{
    vm->instruction_index++;
    registers[IP]++;
}

static int vm_fetch(vmState *vm)
{
    vm_next_instruction(vm);
    return get_value_by_instruction(vm, vm->instructions[registers[IP]]);
}

static int vm_register(vmState *vm)
{
    vm_next_instruction(vm);
    return get_register(vm->instructions[registers[IP]]);
}

void vm_destroy(vmState *vm)
{ // 释放虚拟机运行过程中申请的内存
    for (size_t i = 0; i < DEFAULT_SIZE; i++)
    {
        free(vm->maps[i]);
    }
    for (int i = 0; i < vm->instruction_count; i++)
    {
        free(vm->instructions[i]);
    }
    free(vm);
}

// 虚拟机执行的思路是读取一行，解析一行
void vm_execute(vmState *vm)
{
    // xxxx 执行虚拟机指令
    Instruction *result = malloc(sizeof(Instruction));

    int res = getInstruction(vm, result);
    if (res < 0) {
        printf("instruction parse failed.\n");
        return ;
    }

    // parser(vm, vm->instructions[registers[IP]], result);
    // 解析到对应的字节码，就调用对应的函数

    switch (result->instruction)
    {
    case MOV:
    {
        int reg = vm_register(vm);
        if (reg < 0) {
            printf("invaild register.\n");
            break;
        }
        int number = vm_fetch(vm);
        registers[reg] = number;
        break;
    }
    case ADD:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        int number1 = vm_fetch(vm);
        int number2 = vm_fetch(vm);
        registers[reg] = number1 + number2;
        break;
    }
    case SUB:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        int number1 = vm_fetch(vm);
        int number2 = vm_fetch(vm);
        registers[reg] = number1 - number2;
        break;
    }
    case MUL:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        int number1 = vm_fetch(vm);
        int number2 = vm_fetch(vm);
        registers[reg] = number1 * number2;
        break;
    }
    case MLA:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        int number1 = vm_fetch(vm);
        int number2 = vm_fetch(vm);
        int number3 = vm_fetch(vm);
        registers[reg] = number1 * number2 + number3;
        break;
    }
    case CMP:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        int number = vm_fetch(vm);
        registers[FLAG] = registers[reg] - number;
        break;
    }
    case B:
    {
        // 直接跳过该指令
        vm_fetch(vm);
        break;
    }
    case BEQ:
    {
        if (registers[FLAG] == 0) {
            registers[IP] = vm_fetch(vm);
        }
        break;
    }
    case BNE:
    {
        if (registers[FLAG] != 0)
        {
            registers[IP] = vm_fetch(vm);
        }
        break;
    }
    case BLT:
    {
        if (registers[FLAG] < 0)
        {
            registers[IP] = vm_fetch(vm);
        }
        break;
    }
    case BGT:
    {
        if (registers[FLAG] > 0)
        {
            registers[IP] = vm_fetch(vm);
        }
        break;
    }
    case BL:
    {
        registers[LR] = vm_fetch(vm);
        registers[IP] = registers[LR];
        break;
    }
    case NOP:
    {
        /* code */
        printf("do nothing.\n");
        break;
    }
    case PUSH:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        registers[SP]++;
        registers[SP] = registers[reg];
        break;
    }
    case POP:
    {
        int reg = vm_register(vm);
        if (reg < 0)
        {
            printf("invaild register.\n");
            break;
        }
        registers[reg] = registers[SP];
        registers[SP]--;
        break;
    }
    case SWI:
    {
        int number = vm_fetch(vm);
        vm->is_halt = true; // 终止虚拟机执行
        printf("software interrupt, number is: %d.\n", number);
        break;
    }
    default:
    {
        printf("invaild instruction.\n");
        break;
    }
    }

    free(result);
}

// -f file 传入源文件地址
// -d debug 打开调试模式
int main(int argc, char *argv[])
{ // 虚拟机对象的生命周期只存在于这个main函数里面，main函数结束，虚拟机也就随之结束，并释放相应的内存空间
    if (argc < 2)
    { // 参数个数小于2,说明用户没有传汇编文件
        printf("Must specify an object file to load.\n");
        return -1;
    }

    char *filename = NULL; // 文件名变量

    for (int i = 0; i < argc; i++)
    { // 从命令获取参数
        if (strcmp(argv[i], "-f") >= 0)
        {
            filename = argv[i] + 2; // +2意思是跳过-f
        }
        else if (strcmp(argv[i], "-m") >= 0)
        {
            enable_debug = 1;
        }
    }

    if (strlen(filename) <= 0)
    {
        printf("Must specify an object file to load.\n");
        return -1;
    }

    // 初始化虚拟机
    vmState *vm = vm_init();

    // 打开文件
    FILE *file = fopen(filename, "r");

    // 设置接收文件的缓冲区
    char buffer[LINE_SIZE];
    _clear_buffer(buffer);

    while (!feof(file)) // 判断是否到了文件结尾
    {
        fscanf(file, "%s", buffer); // 按行读取文件，读完一行解析一行
        if (enable_debug == 1)
        { // 如果开启了调试，则打印读取的这一行指令
            printf("%s\n", buffer);
        }

        // 获取这条指令的实际长度
        size_t length = _get_buffer_size(buffer);

        // 解析这一行
        // 解析虚拟机的各种label对应的地址
        parserLine(vm, buffer);

        // 指令条数计数器+1
        vm->instruction_count++;

        // 清空相应空间的内存
        _clear_buffer(buffer);
    }

    // 关闭文件句柄
    fclose(file);

    registers[SP] = -1;
    registers[IP] = 0;
    vm->instruction_index = 0;
    // 遍历虚拟机字节码指令，并执行
    while (vm->is_halt == true)
    {
        vm_execute(vm);
        registers[IP]++;
    }

    // 销毁虚拟机，释放相应内存空间
    vm_destroy(vm);

    return 0;
}
